using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Net;
using System.Threading;

namespace VistaBatterySaver
{
    internal static class Helper
    {
        public static bool IsVistaAeroSupport
        {
            get
            {
                OperatingSystem osInfo = Environment.OSVersion;
                int aver = 0;
                bool ver = NativeMethods.GetProductInfo(osInfo.Version.Major, osInfo.Version.Minor, osInfo.Version.MajorRevision, osInfo.Version.MinorRevision, out aver);

                return !(osInfo.Version.Major != 6 | (ver == true &&
                    (aver == (int)NativeMethods.V6ProductType.PRODUCT_HOME_BASIC |
                    aver == (int)NativeMethods.V6ProductType.PRODUCT_HOME_BASIC_N |
                    aver == (int)NativeMethods.V6ProductType.PRODUCT_UNDEFINED |
                    aver == (int)NativeMethods.V6ProductType.PRODUCT_STARTER)));
            }
        }

        public static bool IsPowerStatusKnown
        {
            get
            {
                return SystemInformation.PowerStatus.PowerLineStatus != PowerLineStatus.Unknown;
            }
        }

        public static bool IsSidebarRunning
        {
            get
            {
                IntPtr[] ptr = GetProcessHandle("sidebar.exe");

                return !(ptr == null || ptr.Length == 0);
            }
        }

        public static bool IsAeroRunning
        {
            get
            {
                return NativeMethods.DwmIsCompositionEnabled();
            }
        }

        internal static bool IsSidebarInStartup
        {
            get
            {
                RegistryKey key = Registry.CurrentUser.OpenSubKey(
                        @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run");
                bool running = key.GetValue("Sidebar", string.Empty).ToString() != string.Empty;
                key.Close();

                return running;
            }
        }

        internal static bool IsFusionEnabled
        {
            get
            {
                try
                {
                    RegistryKey key = Registry.LocalMachine.OpenSubKey(
                                @"SOFTWARE\Microsoft\Fusion");

                    int val = 0;
                    int.TryParse(key.GetValue("EnableLog", 0).ToString(), out val);
                    key.Close();

                    return val == 1;
                }
                catch { }

                return false;
            }
        }

        internal static bool RunInStartup
        {
            set
            {
                RegistryKey key = Registry.CurrentUser.CreateSubKey(
                        @"Software\Microsoft\Windows\CurrentVersion\Run");
                if (value)
                {
                    key.SetValue("VistaBatterySaver", Application.ExecutablePath);
                }
                else
                {
                    key.DeleteValue("VistaBatterySaver", false);
                }
                key.Close();
            }
        }

        public static void EnableSidebar(bool enable)
        {
            IntPtr[] ptr = GetProcessHandle("sidebar.exe");
            if (enable && (ptr == null || ptr.Length == 0))
            {
                Process.Start(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFiles) + @"\Windows Sidebar\sidebar.exe");
            }
            else if (!enable && ptr != null)
            {
                for (int i = 0; i < ptr.Length; i++)
                {
                    CloseProcessTryGracefully(Process.GetProcessById((int)ptr[i]));
                }
            }
        }

        public static void SupressWorkingSet()
        {
            NativeMethods.SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1);
        }

        public static void HideFromTaskManagerWA(IntPtr window)
        {
            NativeMethods.SetWindowLong(window, NativeMethods.GWL_EXSTYLE, NativeMethods.GetWindowLong(window, NativeMethods.GWL_EXSTYLE) | NativeMethods.WS_EX_TOOLWINDOW);
        }

        public static bool HasInternetConnection()
        {
            NativeMethods.InternetConnectionState state = 0;
            return HasInternetConnection(out state);
        }
        public static bool HasInternetConnection(out NativeMethods.InternetConnectionState state)
        {
            state = 0;
            return NativeMethods.InternetGetConnectedState(ref state,0);
        }

        const string CPReleaseURL = "http://www.codeplex.com/vistabattery/Release/ProjectReleases.aspx";
        public static bool HasNewUpdates(int eBuildNumber)
        {
            NativeMethods.InternetConnectionState state = NativeMethods.InternetConnectionState.INTERNET_CONNECTION_OFFLINE;
            if (HasInternetConnection(out state))
            {
                HttpWebRequest req = WebRequest.Create(CPReleaseURL) as HttpWebRequest;
                if (req != null)
                {
                    IAsyncResult stt = req.BeginGetResponse(null, null);
                    DateTime dt = DateTime.Now;
                    while (!stt.IsCompleted | DateTime.Now.Subtract(dt) < TimeSpan.FromSeconds(3))
                    {
                        Thread.Sleep(100);
                        Application.DoEvents();
                    }
                    if (!stt.IsCompleted)
                    {
                        throw new TimeoutException();
                    }

                    HttpWebResponse res = req.EndGetResponse(stt) as HttpWebResponse;
                    if (res.StatusCode == HttpStatusCode.OK)
                    {
                        string[] qn = req.Address.Query.Split('=');
                        int ores = eBuildNumber;
                        if(qn.Length > 1 && int.TryParse(qn[1],out ores) && ores != eBuildNumber)
                        {
                            return true;
                        }
                    }
                }
                
            }
            return false;
        }

        public static void CloseProcessTryGracefully(Process proc)
        {
            if (proc.MainWindowHandle == IntPtr.Zero)
            {
                foreach (ProcessThread pt in proc.Threads)
                {
                    NativeMethods.EnumThreadWindows((uint)pt.Id, new NativeMethods.EnumThreadDelegate(EnumThreadCallback), IntPtr.Zero);                    
                }
            }
            else if (proc.CloseMainWindow())
            {
                proc.Close();
            }

            //not exited. Kill
            if (proc != null && !proc.HasExited)
                proc.Kill();
        }
        static bool EnumThreadCallback(IntPtr hWnd, IntPtr lParam)
        {
            return NativeMethods.PostMessage(hWnd, NativeMethods.WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
        }


        public static IntPtr[] GetProcessHandle(string applicationName)
        {
            List<IntPtr> m_hndls = new List<IntPtr>();
            IntPtr handle = IntPtr.Zero;
            try
            {
                handle = NativeMethods.CreateToolhelp32Snapshot(NativeMethods.TH32CS_SNAPPROCESS, 0);
                NativeMethods.PROCESSENTRY32 info = new NativeMethods.PROCESSENTRY32();
                info.dwSize = (uint)System.Runtime.InteropServices.
                              Marshal.SizeOf(typeof(NativeMethods.PROCESSENTRY32));

                int first = NativeMethods.Process32First(handle, ref info);
                if (first == 0)
                    return null;

                do
                {
                    if (string.Compare(info.szExeFile,
                          applicationName, true) == 0)
                    {
                        //return handle;
                        m_hndls.Add(new IntPtr(info.th32ProcessID));
                        //Return
                        return m_hndls.ToArray();
                        //handle);
                        //new IntPtr(info.th32ProcessID));
                    }
                }
                while (NativeMethods.Process32Next(handle, ref info) != 0);
            }
            catch
            {
                throw;
            }
            finally
            {
                NativeMethods.CloseHandle(handle);
                handle = IntPtr.Zero;
            }
            return m_hndls.ToArray();
        }

        internal static Dictionary<Guid,string> GetPowerEnumeration()
        {
            Guid SchemeGuid = Guid.Empty;
            uint index = 0;
            uint BufferSize = (uint)Marshal.SizeOf(SchemeGuid);
           

            Dictionary<Guid, string> schemes = new Dictionary<Guid, string>();
            while (0 == NativeMethods.PowerEnumerate((IntPtr)null, (IntPtr)null, (IntPtr)null, NativeMethods.POWER_DATA_ACCESSOR.ACCESS_SCHEME, index, ref SchemeGuid, ref BufferSize))
            {
                schemes.Add(SchemeGuid, GetPowerName(SchemeGuid));

                index++;
            }

            return schemes;
        }

        internal static string GetPowerName(Guid SchemeGuid)
        {
            string name = string.Empty;
            IntPtr lpszName = (IntPtr)null;
            uint dwSize = 0;
            NativeMethods.PowerReadFriendlyName((IntPtr)null, ref SchemeGuid, (IntPtr)null, (IntPtr)null, lpszName, ref dwSize);
            if (dwSize > 0)
            {
                lpszName = Marshal.AllocHGlobal((int)dwSize);
                if (0 == NativeMethods.PowerReadFriendlyName((IntPtr)null, ref SchemeGuid, (IntPtr)null, (IntPtr)null, lpszName, ref dwSize))
                {
                    name = Marshal.PtrToStringUni(lpszName);
                }
                if (lpszName != IntPtr.Zero)
                    Marshal.FreeHGlobal(lpszName);
            }

            return name;
        }

        

        internal static KeyValuePair<Guid,string> GetActivePower()
        {
            KeyValuePair<Guid, string> active = new KeyValuePair<Guid, string>();
            Guid ActiveScheme = Guid.Empty;
            IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
            if (0 == NativeMethods.PowerGetActiveScheme((IntPtr)null, out ptr))
            {
                ActiveScheme = (Guid)Marshal.PtrToStructure(ptr, typeof(Guid));

                active = new KeyValuePair<Guid, string>(ActiveScheme, GetPowerName(ActiveScheme));

                if (ptr != null)
                {
                    Marshal.FreeHGlobal(ptr);
                }
            }

            return active;

        }

        internal static void SetActivePower(Guid scheme)
        {
            NativeMethods.PowerSetActiveScheme((IntPtr)null, ref scheme);
        }

        internal static bool CheckEntryPoint(string library, string method)
        {
            IntPtr libPtr = NativeMethods.LoadLibrary(library);
            if (!libPtr.Equals(System.IntPtr.Zero))
            {
                if (!NativeMethods.GetProcAddress(libPtr, method).Equals(System.IntPtr.Zero))
                {
                    NativeMethods.FreeLibrary(libPtr);
                    return (true);
                }
                NativeMethods.FreeLibrary(libPtr);
            }
            return (false);
        }

        internal static void InstallNewVersion()
        {
            //TODO: uninstall & install
            Console.WriteLine();

        }
    }
}
